package com.zf.yichat.config.utils;

import com.aliyun.oss.ClientConfiguration;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.common.auth.DefaultCredentialProvider;
import com.aliyun.oss.model.CannedAccessControlList;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.PutObjectResult;
import lombok.extern.slf4j.Slf4j;
import net.sourceforge.pinyin4j.PinyinHelper;
import org.apache.commons.lang3.StringUtils;
import org.apache.tomcat.util.http.fileupload.FileItemStream;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Date;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @Description: 阿里云 oss
 * @Date: 2019/5/10
 */
@Slf4j
@Component
public class OssBootUtil {

    @Value("${st.oss.endpoint}")
    private String endpoint;
    @Value("${st.oss.accessKey}")
    private String accessKeyId;
    @Value("${st.oss.secretKey}")
    private String accessKeySecret;
    @Value("${st.oss.bucketName}")
    private String bucketName;
    @Value("${st.oss.Domain}")
    private String Domain;


    /**
     * oss 工具客户端
     */
    private  OSSClient ossClient = null;

    /**
     * 上传文件至阿里云 OSS
     * 文件上传成功,返回文件完整访问路径
     * 文件上传失败,返回 null
     *
     * @param file    待上传文件
     * @param fileDir 文件保存目录
     * @return oss 中的相对文件路径
     */
    public  String upload(MultipartFile file, String fileDir,String customBucket) {
        String FILE_URL = null;
        initOSS(endpoint, accessKeyId, accessKeySecret);
        StringBuilder fileUrl = new StringBuilder();
        String newBucket = bucketName;
        if(StringUtils.isNotEmpty(customBucket)){
            newBucket = customBucket;
        }
        try {
            //判断桶是否存在,不存在则创建桶
            if(!ossClient.doesBucketExist(newBucket)){
                ossClient.createBucket(newBucket);
            }

            // 获取文件名
            String orgName = file.getOriginalFilename();
            if("" == orgName){
              orgName=file.getName();
            }
            orgName = getFileName(orgName);

            boolean containsChinese = containsChinese(orgName);
            if (containsChinese) {
                orgName = convertToPinyin(orgName);
                orgName = orgName.replaceAll("\\s", "");
            }

            String fileName = orgName.substring(0, orgName.lastIndexOf(".")) + "_" + System.currentTimeMillis() + orgName.substring(orgName.indexOf("."));
            if (!fileDir.endsWith("/")) {
                fileDir = fileDir.concat("/");
            }
            fileUrl = fileUrl.append(fileDir + fileName);

            if (StringUtils.isNotEmpty(Domain) && Domain.toLowerCase().startsWith("http")) {
                FILE_URL = Domain + "/" + fileUrl;
            } else {
                FILE_URL = "https://" + newBucket + "." + endpoint + "/" + fileUrl;
            }
            PutObjectResult result = ossClient.putObject(newBucket, fileUrl.toString(), file.getInputStream());
            // 设置权限(公开读)
            ossClient.setBucketAcl(newBucket, CannedAccessControlList.PublicRead);
            if (result != null) {
                log.info("------OSS文件上传成功------" + fileUrl);
            }
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
        return FILE_URL;
    }

    private boolean containsChinese(String str) {
        Pattern pattern = Pattern.compile("[\u4e00-\u9fa5]");
        Matcher matcher = pattern.matcher(str);
        return matcher.find();
    }

    private String convertToPinyin(String chinese) {
        StringBuilder pinyin = new StringBuilder();

        for (char c : chinese.toCharArray()) {
            String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(c);

            if (pinyinArray != null && pinyinArray.length > 0) {
                // 取第一个拼音，并去除声调数字
                String pinyinWithoutTone = pinyinArray[0].replaceAll("\\d", "");
                pinyin.append(pinyinWithoutTone);
            } else {
                // 如果字符不是汉字，则保持原样
                pinyin.append(c);
            }
        }

        return pinyin.toString();
    }
    /**
     * 文件上传
     * @param file
     * @param fileDir
     * @return
     */
    public  String upload(MultipartFile file, String fileDir) {
        return upload(file, fileDir,null);
    }

    /**
     * 上传文件至阿里云 OSS
     * 文件上传成功,返回文件完整访问路径
     * 文件上传失败,返回 null
     *
     * @param file    待上传文件
     * @param fileDir 文件保存目录
     * @return oss 中的相对文件路径
     */
    public  String upload(FileItemStream file, String fileDir) {
        String FILE_URL = null;
        initOSS(endpoint, accessKeyId, accessKeySecret);
        StringBuilder fileUrl = new StringBuilder();
        try {
            String suffix = file.getName().substring(file.getName().lastIndexOf('.'));
            String fileName = UUID.randomUUID().toString().replace("-", "") + suffix;
            if (!fileDir.endsWith("/")) {
                fileDir = fileDir.concat("/");
            }
            fileUrl = fileUrl.append(fileDir + fileName);

            if (StringUtils.isNotEmpty(Domain) && Domain.toLowerCase().startsWith("http")) {
                FILE_URL = Domain + "/" + fileUrl;
            } else {
                FILE_URL = "https://" + bucketName + "." + endpoint + "/" + fileUrl;
            }
            PutObjectResult result = ossClient.putObject(bucketName, fileUrl.toString(), file.openStream());
            // 设置权限(公开读)
            ossClient.setBucketAcl(bucketName, CannedAccessControlList.PublicRead);
            if (result != null) {
                log.info("------OSS文件上传成功------" + fileUrl);
            }
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
        return FILE_URL;
    }

    /**
     * 删除文件
     * @param url
     */
    public  void deleteUrl(String url) {
        deleteUrl(url,null);
    }

    /**
     * 删除文件
     * @param url
     */
    public  void deleteUrl(String url,String bucket) {
        String newBucket = bucketName;
        if(StringUtils.isNotEmpty(bucket)){
            newBucket = bucket;
        }
        String bucketUrl = "";
        if (StringUtils.isNotEmpty(Domain) && Domain.toLowerCase().startsWith("http")) {
            bucketUrl = Domain + "/" ;
        } else {
            bucketUrl = "https://" + newBucket + "." + endpoint + "/";
        }
        url = url.replace(bucketUrl,"");
        ossClient.deleteObject(newBucket, url);
    }

    /**
     * 删除文件
     * @param fileName
     */
    public  void delete(String fileName) {
        ossClient.deleteObject(bucketName, fileName);
    }

    /**
     * 获取文件流
     * @param objectName
     * @param bucket
     * @return
     */
    public  InputStream getOssFile(String objectName,String bucket){
        InputStream inputStream = null;
        try{
            String newBucket = bucketName;
            if(StringUtils.isNotEmpty(bucket)){
                newBucket = bucket;
            }
            initOSS(endpoint, accessKeyId, accessKeySecret);
            OSSObject ossObject = ossClient.getObject(newBucket,objectName);
            inputStream = new BufferedInputStream(ossObject.getObjectContent());
        }catch (Exception e){
            log.info("文件获取失败" + e.getMessage());
        }
        return inputStream;
    }

    /**
     * 获取文件流
     * @param objectName
     * @return
     */
    public  InputStream getOssFile(String objectName){
        return getOssFile(objectName,null);
    }

    /**
     * 获取文件外链
     * @param bucketName
     * @param objectName
     * @param expires
     * @return
     */
    public  String getObjectURL(String bucketName, String objectName, Date expires) {
        initOSS(endpoint, accessKeyId, accessKeySecret);
        try{
            if(ossClient.doesObjectExist(bucketName,objectName)){
                URL url = ossClient.generatePresignedUrl(bucketName,objectName,expires);
                return URLDecoder.decode(url.toString(),"UTF-8");
            }
        }catch (Exception e){
            log.info("文件路径获取失败" + e.getMessage());
        }
        return null;
    }


    /**
     * 初始化 oss 客户端
     *
     * @return
     */
    private  OSSClient initOSS(String endpoint, String accessKeyId, String accessKeySecret) {
        if (ossClient == null) {
            ossClient = new OSSClient(endpoint,
                    new DefaultCredentialProvider(accessKeyId, accessKeySecret),
                    new ClientConfiguration());
        }
        return ossClient;
    }


    /**
     * 上传文件到oss
     * @param stream
     * @param relativePath
     * @return
     */
    public  String upload(InputStream stream, String relativePath) {
        String FILE_URL = null;
        String fileUrl = relativePath;
        initOSS(endpoint, accessKeyId, accessKeySecret);
        if (StringUtils.isNotEmpty(Domain) && Domain.toLowerCase().startsWith("http")) {
            FILE_URL = Domain + "/" + relativePath;
        } else {
            FILE_URL = "https://" + bucketName + "." + endpoint + "/" + fileUrl;
        }
        PutObjectResult result = ossClient.putObject(bucketName, fileUrl.toString(),stream);
        // 设置权限(公开读)
        ossClient.setBucketAcl(bucketName, CannedAccessControlList.PublicRead);
        if (result != null) {
            log.info("------OSS文件上传成功------" + fileUrl);
        }
        return FILE_URL;
    }

    public  String getFileName(String fileName){
        //判断是否带有盘符信息
        // Check for Unix-style path
        int unixSep = fileName.lastIndexOf('/');
        // Check for Windows-style path
        int winSep = fileName.lastIndexOf('\\');
        // Cut off at latest possible point
        int pos = (winSep > unixSep ? winSep : unixSep);
        if (pos != -1)  {
            // Any sort of path separator found...
            fileName = fileName.substring(pos + 1);
        }
        //替换上传文件名字的特殊字符
        fileName = fileName.replace("=","").replace(",","").replace("&","").replace("#", "");
        return fileName;
    }

}
